import pandas as pd
import math
import os
import re
from config import AppConfig
class ProcessData:
    def __init__(self):
        self.config = AppConfig()
        
    def process_file(self, file_path):
        """处理单个测量文件的核心方法"""
           
        # 读取并解析文件
        self._read_and_parse_file(file_path)
            
        self._merge_ec1_and_pos_data()
       
    def _read_and_parse_file(self, file_path):
        """读取并解析文件，使用传入的file_path参数"""
        dmnum = self.config.dmnum
        # print(f"正在处理文件: {file_path}")
        
        with open(file_path, 'r') as note:
            ec1_regex = re.compile(r"\bEC1 1.+")
            pos_regex = re.compile(r"\bPOS .+")

            for line in note:
                
                if ec1_regex.findall(line):
                    ec1_fields = ec1_regex.findall(line)[0].split(" ")
                    ec1_fields[2] = round(float(ec1_fields[2]), 3)  #时间  过午夜零点的秒数
                    ec1_fields[3] = '-' + ec1_fields[3]
                    ec1_fields[3] = round(float(ec1_fields[3]), 2)  #水深
                    result = [ec1_fields[2], ec1_fields[3]]
                    self.config.EC1[dmnum].append(result)
                
                if pos_regex.findall(line):
                    pos_fields = pos_regex.findall(line)[0].split(" ")
                    pos_fields[2] = round(float(pos_fields[2]), 3)   #时间  过午夜零点的秒数
                    pos_fields[3] = round(float(pos_fields[3]), 3)   #E
                    pos_fields[4] = round(float(pos_fields[4]), 3)   #N
                    result = [pos_fields[2], pos_fields[3], pos_fields[4]]
                    self.config.POS[dmnum].append(result)
                
    def _merge_ec1_and_pos_data(self):
        """
        将EC1高程数据与POS坐标数据根据时间戳进行拼接
        利用EC1和POS数据均已按时间升序排列的特性，使用双指针技术优化匹配算法
        时间复杂度从O(n*m)降低到O(n+m)
        """
        dmnum = self.config.dmnum
        
        # 检查数据是否存在
        if len(self.config.EC1[dmnum]) == 0 or len(self.config.POS[dmnum]) == 0:
            print(f"警告: EC1或POS数据为空，无法进行数据拼接")
            return []
        
        merged_data = []
        # 最大时间差限制（秒），可以根据需要调整
        max_time_difference = 2.0  # 设定的时间限制
        
        # 双指针实现，利用数据已排序的特性
        pos_idx = 0  # POS数据的当前指针位置
        ec1_len = len(self.config.EC1[dmnum])
        pos_len = len(self.config.POS[dmnum])
        
        # 遍历EC1数据
        for ec1_idx in range(ec1_len):
            ec1_point = self.config.EC1[dmnum][ec1_idx]
            ec1_time = ec1_point[0]  # EC1时间戳
            ec1_depth = ec1_point[1]  # 水深/高程
            
            # 初始化匹配标志和最佳匹配
            best_pos_point = None
            min_abs_time_diff = float('inf')
            
            # 由于数据已排序，我们只需要从当前pos_idx开始查找
            # 首先移动pos_idx到可能的起始位置（POS时间不早于EC1时间减去max_time_difference）
            while (pos_idx < pos_len - 1 and 
                  self.config.POS[dmnum][pos_idx][0] < ec1_time - max_time_difference):
                pos_idx += 1
            
            # 检查当前位置及其后续几个位置（因为数据已排序，超出max_time_difference后可以停止）
            temp_idx = pos_idx
            while temp_idx < pos_len:
                pos_point = self.config.POS[dmnum][temp_idx]
                pos_time = pos_point[0]
                
                # 如果POS时间已经超过EC1时间+max_time_difference，可以提前退出循环
                if pos_time > ec1_time + max_time_difference:
                    break
                
                # 计算时间差绝对值
                abs_time_diff = abs(pos_time - ec1_time)
                
                # 如果在时间限制内
                if abs_time_diff <= max_time_difference:
                    if abs_time_diff < min_abs_time_diff:
                        min_abs_time_diff = abs_time_diff
                        best_pos_point = pos_point
                
                temp_idx += 1
            
            # 如果找到匹配的POS点，添加到合并数据中
            if best_pos_point:
                pos_e = best_pos_point[1]
                pos_n = best_pos_point[2]
                merged_data.append([ec1_time, pos_e, pos_n, ec1_depth])
        
        # 将合并数据存储到config对象中
        if merged_data:
            # 确保config对象有merged_ec1_pos属性
            if not hasattr(self.config, 'merged_ec1_pos'):
                self.config.merged_ec1_pos = None
            # 转换为DataFrame
            self.config.merged_ec1_pos = pd.DataFrame(merged_data)
            self.config.merged_ec1_pos.columns = ['时间', 'E', 'N', '水深']
        
        matched_count = len(merged_data)
        unmatched_count = ec1_len - matched_count
        # print(f"EC1与POS数据匹配完成: 匹配成功 {matched_count} 个，未匹配 {unmatched_count} 个，EC1总点数: {ec1_len}")
        return merged_data
    
    def generate_fix_points(self, point_distance=20.0, use_interpolation=True):
        """
        根据指定的点距生成FIX点
        
        参数:
            point_distance: 点距参数，默认为20.0
            use_interpolation: 是否使用线性内插来提高精度，默认为True
        
        返回:
            fix_points: 生成的FIX点列表
        """
        dmnum = self.config.dmnum
        
        # 确保FIX字典存在
        if not hasattr(self.config, 'FIX'):
            self.config.FIX = {}
        
        # 初始化当前测深仪的FIX点列表
        self.config.FIX[dmnum] = []
        
        # 尝试从ys_piont获取数据，如果不存在则使用merged_ec1_pos
        data_source = None
        if hasattr(self.config, 'ys_piont') and self.config.ys_piont is not None:
            data_source = self.config.ys_piont
        elif hasattr(self.config, 'merged_ec1_pos') and self.config.merged_ec1_pos is not None:
            data_source = self.config.merged_ec1_pos.values
        else:
            print("警告: 没有找到可用的数据源，无法生成FIX点")
            return []
        
        if len(data_source) < 2:
            print("警告: 数据点数量不足，无法生成FIX点")
            if len(data_source) == 1:
                # 如果只有一个点，直接作为FIX点
                self.config.FIX[dmnum].append(data_source[0])
            return self.config.FIX[dmnum]
        
        # 计算每个点到第一个点的累积距离
        cumulative_distances = [0.0]
        for i in range(1, len(data_source)):
            # 假设数据格式为 [时间, E, N, 水深]
            e_prev, n_prev = data_source[i-1][1], data_source[i-1][2]
            e_curr, n_curr = data_source[i][1], data_source[i][2]
            # 计算两点之间的距离
            dist = math.sqrt((e_curr - e_prev)**2 + (n_curr - n_prev)** 2)
            cumulative_distances.append(cumulative_distances[-1] + dist)
        
        # 生成FIX点
        fix_points = [data_source[0].tolist() if hasattr(data_source[0], 'tolist') else list(data_source[0])]
        current_target_distance = point_distance
        
        # 使用双指针技术查找FIX点
        data_idx = 1  # 从第二个点开始
        
        while data_idx < len(data_source) - 1:
            # 找到第一个累积距离大于等于目标距离的点
            while data_idx < len(data_source) and cumulative_distances[data_idx] < current_target_distance:
                data_idx += 1
            
            # 如果已经到达最后一个点，跳出循环
            if data_idx >= len(data_source) - 1:
                break
            
            # 此时，data_idx-1点的累积距离 < 目标距离 <= data_idx点的累积距离
            # 如果不使用内插，直接选择data_idx点
            if not use_interpolation:
                fix_points.append(data_source[data_idx].tolist() if hasattr(data_source[data_idx], 'tolist') else list(data_source[data_idx]))
                current_target_distance += point_distance
            else:
                # 使用线性内插
                prev_point = data_source[data_idx - 1]
                curr_point = data_source[data_idx]
                prev_dist = cumulative_distances[data_idx - 1]
                curr_dist = cumulative_distances[data_idx]
                
                # 计算内插比例
                ratio = (current_target_distance - prev_dist) / (curr_dist - prev_dist)
                
                # 对各参数进行线性内插
                interp_time = prev_point[0] + ratio * (curr_point[0] - prev_point[0])
                interp_e = prev_point[1] + ratio * (curr_point[1] - prev_point[1])
                interp_n = prev_point[2] + ratio * (curr_point[2] - prev_point[2])
                interp_depth = prev_point[3] + ratio * (curr_point[3] - prev_point[3])
                
                # 创建内插点
                interpolated_point = [interp_time, interp_e, interp_n, interp_depth]
                fix_points.append(interpolated_point)
                current_target_distance += point_distance
        
        # 添加最后一个点作为FIX点
        last_point = data_source[-1].tolist() if hasattr(data_source[-1], 'tolist') else list(data_source[-1])
        # 检查最后一个点是否已经在FIX点列表中
        if not fix_points or not all(abs(last_point[i] - fix_points[-1][i]) < 1e-6 for i in range(len(last_point))):
            fix_points.append(last_point)
        
        # 保存FIX点到配置中
        self.config.FIX[dmnum] = fix_points
        
        print(f"FIX点生成完成: 共生成 {len(fix_points)} 个FIX点")
        return fix_points

   